﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Infrastructure.Extensions
{
    public static class LinqExtensions
    {
        // 用于替换表达式参数的类
        private class ParameterRebinder : ExpressionVisitor
        {
            private readonly Dictionary<ParameterExpression, ParameterExpression> map;

            // 构造函数，初始化参数映射
            private ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            // 静态方法，替换表达式中的参数
            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            // 重写VisitParameter方法，替换参数表达式
            protected override Expression VisitParameter(ParameterExpression p)
            {
                if (map.TryGetValue(p, out var value))
                {
                    p = value; // 替换参数
                }
                return base.VisitParameter(p);
            }
        }

        // 扩展方法，获取属性表达式
        public static Expression Property(this Expression expression, string propertyName)
        {
            return Expression.Property(expression, propertyName);
        }

        // 扩展方法，生成与逻辑操作表达式
        public static Expression AndAlso(this Expression left, Expression right)
        {
            return Expression.AndAlso(left, right);
        }

        // 扩展方法，生成方法调用表达式
        public static Expression Call(this Expression instance, string methodName, params Expression[] arguments)
        {
            return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);
        }

        // 扩展方法，生成大于比较表达式
        public static Expression GreaterThan(this Expression left, Expression right)
        {
            return Expression.GreaterThan(left, right);
        }

        // 扩展方法，将表达式转换为 Lambda 表达式
        public static Expression<T> ToLambda<T>(this Expression body, params ParameterExpression[] parameters)
        {
            return Expression.Lambda<T>(body, parameters);
        }

        // 扩展方法，返回始终为 true 的 Lambda 表达式
        public static Expression<Func<T, bool>> True<T>()
        {
            return (T param) => true;
        }

        // 扩展方法，返回始终为 false 的 Lambda 表达式
        public static Expression<Func<T, bool>> False<T>()
        {
            return (T param) => false;
        }

        // 扩展方法，将两个 Lambda 表达式合并为与操作
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        // 扩展方法，将两个 Lambda 表达式合并为或操作
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        // 合并两个表达式，使用指定的逻辑操作符（与或或）
        private static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // 创建一个参数映射，映射第二个表达式的参数到第一个表达式的参数
            Dictionary<ParameterExpression, ParameterExpression> map = first.Parameters.Select((ParameterExpression f, int i) => new
            {
                f = f,
                s = second.Parameters[i]
            }).ToDictionary(p => p.s, p => p.f);

            // 替换第二个表达式中的参数
            Expression arg = ParameterRebinder.ReplaceParameters(map, second.Body);

            // 返回合并后的 Lambda 表达式
            return Expression.Lambda<T>(merge(first.Body, arg), first.Parameters);
        }
    }
}
